package com.net.xpay.admin;

import com.net.common.util.SerializationUtil;
import com.net.xpay.common.annotation.OperateLog;
import com.net.xpay.common.domain.OperationRecord;
import com.net.xpay.common.domain.admin.rbac.AdminUser;
import com.net.xpay.common.manager.OperationRecordManager;
import com.net.xpay.common.manager.admin.rbac.AdminUserManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @description: 自定义接口aop

 * @create: 2020-10-20 11:08
 **/
@Component
@Aspect
public class CustomInterfaceAop {

    @Autowired
    private OperationRecordManager operationRecordManager;

    @Autowired
    private AdminUserManager adminUserManager;

    /**
     * 编写切入点表达式
     */
    @Pointcut(value = "@annotation(com.net.xpay.common.annotation.OperateLog)")
    public void operateLogPoint(){}


    /**
     * @Description:[方法执行前获取到方法的相关信息]
     * @param joinPoint : 切入点
     * @return void
     * @date 2020/10/20 11:12
     */
    @Before("operateLogPoint()")
    public void recordMethodInfo(JoinPoint joinPoint){
        // 获取到路由信息
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert requestAttributes != null;
        HttpServletRequest request = requestAttributes.getRequest();
        String requestUrl = request.getRequestURI();
        // 获取到Method对象
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method targetMethod = methodSignature.getMethod();
        // 获取OperateLog注解,然后获取到里面的备注信息
        OperateLog operateLog = targetMethod.getAnnotation(OperateLog.class);
        String desc = operateLog.methodDesc();
        // 获取入参信息封装为map然后序列化为string
        Object[] args = joinPoint.getArgs();
        Parameter[] parameters = targetMethod.getParameters();
        Map<String,Object> paramMap;
        paramMap = IntStream.range(0, args.length)
                .boxed()
                .filter(j -> {
                    Object arg = args[j];
                    if (Objects.nonNull(arg) && arg instanceof HttpServletRequest) {
                        return false;
                    }
                    if (Objects.nonNull(arg) && arg instanceof HttpServletResponse) {
                        return false;
                    }

                    return true;
                })
                .collect(Collectors.toMap( j -> parameters[j].getName(),j -> args[j]));
        String paramString = SerializationUtil.obj2String(paramMap);
        // 通过权限获取当前用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Long adminUserId = (Long)authentication.getPrincipal();
        AdminUser adminUser = adminUserManager.findById(adminUserId);
        // 创建实体类对象
        OperationRecord operationRecord = new OperationRecord();
        // 封装对象
        operationRecord.setInterfaceUrl(requestUrl);
        operationRecord.setInParam(paramString);
        operationRecord.setMethodType(operateLog.methodType());
        operationRecord.setMethodDesc(adminUser.getUsername() + desc);
        operationRecord.setAdminUserId(adminUser.getId());
        operationRecord.setModule(operateLog.module());
        operationRecord.setUsername(adminUser.getUsername());
        operationRecord.setMobile(adminUser.getMobile());
        // 数据入库
        operationRecordManager.save(operationRecord);
    }

}
